﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Printing;
using System.Threading;

namespace RestaurateurConsole
{
    public partial class PrintBill : Form
    {
        decimal amount = (decimal)0;
        decimal taxes;
        decimal total;
        int billNo;
        IEnumerable<ABill> data;
        string Account;
        PrintDocument pd = new PrintDocument();

        List<string> dataFormattedForPrint = new List<string>();
        const int NumOfCharsPerLine = 50;

        public PrintBill()
        {
            InitializeComponent();
        }

        public PrintBill(IEnumerable<ABill> Data, int BillNo, string Account)
        {
            this.Account = Account;
            billNo = BillNo;
            InitializeComponent();
            grid.Columns.Add(Item);
            grid.Columns.Add(Price);
            grid.Columns.Add(Quantity);
            grid.Columns.Add(new DataGridViewTextBoxColumn() { Name = "Amount" });

            data = Data;

            foreach (var a in Data)
            {
                DataGridViewRow row = new DataGridViewRow();
                
                DataGridViewCell cell1 = new DataGridViewTextBoxCell() { Value =  String.IsNullOrEmpty(a.Item) ? a.OtherItem : a.Item };
                DataGridViewCell cell2 = new DataGridViewTextBoxCell() { Value = a.Price };
                DataGridViewCell cell3 = new DataGridViewTextBoxCell() { Value = a.Quantity };
                DataGridViewCell cell4 = new DataGridViewTextBoxCell() { Value = a.Amount };
                row.Cells.Add(cell1);
                row.Cells.Add(cell2);
                row.Cells.Add(cell3);
                row.Cells.Add(cell4);
                grid.Rows.Add(row);

                amount += a.Amount;
            }
            taxes = amount > ConfigHandler.Configuration.TaxAdditionThreshhold ? amount * ConfigHandler.Configuration.TaxRate / (decimal)100 : (decimal)0;
            total = amount + taxes;
            table.Controls.Add(new Label() { Text = "Total:" });
            table.Controls.Add(new Label() { Text = String.Format("Rs {0}", amount) });
            table.Controls.Add(new Label() { Text = String.Format("Taxes ({0}%):", ConfigHandler.Configuration.TaxRate) });
            table.Controls.Add(new Label() { Text = String.Format("Rs {0}", taxes) });
            table.Controls.Add(new Label() { Text = "Total:" });
            table.Controls.Add(new Label() { Text = String.Format("Rs {0}", total) });
            FormatForPrint();
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            Print();
        }

        public void Print()
        {
            Thread t = new Thread(new ThreadStart(StartPrint));
            t.Start();
        }

        private void StartPrint()
        {
            PageSetupDialog psd = new PageSetupDialog();
            psd.Document = pd;

            int multiplier = 1;
            multiplier = (int)Math.Ceiling((double)dataFormattedForPrint.Count / (double)26);
            psd.PageSettings.PaperSize = new PaperSize("Bill", 400, (400 * multiplier) + 150);
            psd.PageSettings.PaperSize.RawKind = (int)PaperKind.Custom;
            psd.PageSettings.PaperSize.Width = 400;
            psd.PageSettings.PaperSize.Height = (400 * multiplier) + 150;

            pd.DefaultPageSettings.Margins.Left = 35;
            pd.DefaultPageSettings.Margins.Top = 10;
            pd.DefaultPageSettings.Margins.Right = 10;
            pd.DefaultPageSettings.Margins.Bottom = 10;

            pd.DocumentName = String.Format("Restaurateur: Bill No: {0}", billNo);
            pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
            pd.Print();
        }

        public void Initialize()
        {
            dataFormattedForPrint.Clear();
        }

        public void AddToPrint(string data)
        {
            dataFormattedForPrint.Add(data);
        }

        private void FormatForPrint()
        {
            if (dataFormattedForPrint.Count == 0)
            {
                dataFormattedForPrint.Add(CenterLine("SALT N' PEPPER", 35));
                foreach (var line in ConfigHandler.Configuration.Address)
                {
                    dataFormattedForPrint.Add(CenterLine(line, 35));
                }
                dataFormattedForPrint.Add(CenterLine("Phone: " + ConfigHandler.Configuration.PhoneNumber, 35));
                dataFormattedForPrint.Add(Repeat("-", 35));

                dataFormattedForPrint.Add(LeftLine("Bill: " + billNo.ToString(), 10) + RightLine(DateTime.Now.ToString(), 25));
                if (!String.IsNullOrEmpty(this.Account))
                {
                    if (this.Account.Length <= 20)
                        dataFormattedForPrint.Add(LeftLine("Customer:", 15) + LeftLine(this.Account, 20));
                    else
                        dataFormattedForPrint.Add(LeftLine(String.Format("Customer: {0}", this.Account), 35));
                }
                dataFormattedForPrint.Add(Repeat("-", 35));

                var strItem = LeftLine("Item Name", 20);
                var strPrice = CenterLine("Rate", 5);
                var strQuantity = CenterLine("Qty", 5);
                var strAmount = CenterLine("Price", 5);

                dataFormattedForPrint.Add(strItem + strPrice + strQuantity + strAmount);
                dataFormattedForPrint.Add(Repeat(" ", 35));
                

                foreach (var item in data)
                {
                    var name = LeftLine(String.IsNullOrEmpty(item.OtherItem) ? item.Item : item.OtherItem, 20);
                    var qty = CenterLine(item.Price.ToString(), 5);
                    var amt = CenterLine(item.Quantity.ToString(), 5);
                    var prc = CenterLine(item.Amount.ToString(), 5);
                    dataFormattedForPrint.Add(name + qty + amt + prc);
                }

                dataFormattedForPrint.Add(Repeat("-", 35));

                dataFormattedForPrint.Add(RightLine(String.Format("Price: Rs {0}", amount), 35));
                dataFormattedForPrint.Add(RightLine(String.Format("Tax ({0}%): Rs {1}", ConfigHandler.Configuration.TaxRate, taxes), 35));
                dataFormattedForPrint.Add(RightLine(String.Format("Total: Rs {0}", total), 35));

                dataFormattedForPrint.Add(Repeat("-", 35));
                
                foreach (var line in dataFormattedForPrint)
                {
                    Console.WriteLine(line);
                }
            }
        }

        public string RightLine(string p, int lineLength)
        {
            if (String.IsNullOrEmpty(p))
                return Repeat(" ", lineLength);
            if (p.Length == lineLength)
                return p;
            else if (p.Length > lineLength)
                return p.Substring(0, lineLength);
            else
                return Repeat(" ", lineLength - p.Length) + p;
        }


        public string CenterLine(string p, int lineLength)
        {
            if (String.IsNullOrEmpty(p))
                return Repeat(" ", lineLength);
            if (p.Length == lineLength)
                return p;
            else if (p.Length > lineLength)
                return p.Substring(0, lineLength);
            else
            {
                var l = p.Length;
                var requiredBlanks = lineLength - l;
                var blanksOnLeft = (int)Math.Ceiling(requiredBlanks / (double)2);
                var blanksOnRight = (int)Math.Floor(requiredBlanks / (double)2);
                return GetBlanks(blanksOnLeft) + p + GetBlanks(blanksOnRight);
            }
        }

        public string LeftLine(string p, int lineLength)
        {
            if (String.IsNullOrEmpty(p))
                return Repeat(" ", lineLength);
            int len = p.Length;
            if (len < lineLength)
                return p + Repeat(" ", lineLength - len);
            else if (len == lineLength)
                return p;
            else
                return p.Substring(0, lineLength);
        }

        public string GetBlanks(int length)
        {
            return Repeat(" ", length);
        }

        public string Repeat(string chr, int length)
        {
            string s = "";
            for (int i = 0; i < length; ++i)
                s += chr;
            return s;
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            try
            {
                PrintPreview();
            }
            catch (Exception x)
            {
                MessageBox.Show(x.Message);
            }
        }

        public void PrintPreview()
        {
            PrintPreviewDialog ppd = new PrintPreviewDialog();
            PageSetupDialog psd = new PageSetupDialog();
            psd.Document = pd;

            int multiplier = 1;
            multiplier = (int)Math.Ceiling((double)dataFormattedForPrint.Count / (double)26);
            psd.PageSettings.PaperSize = new PaperSize("Bill", 400, 400 * multiplier);
            psd.PageSettings.PaperSize.RawKind = (int)PaperKind.Custom;
            psd.PageSettings.PaperSize.Width = 400;
            psd.PageSettings.PaperSize.Height = 400 * multiplier;

            pd.DefaultPageSettings.Margins.Left = 35;
            pd.DefaultPageSettings.Margins.Top = 10;
            pd.DefaultPageSettings.Margins.Right = 10;
            pd.DefaultPageSettings.Margins.Bottom = 10;

            pd.DocumentName = "Bill";
            pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
            
            ppd.Document = pd;
            try
            {
                ppd.ShowDialog();
            }
            catch (InvalidPrinterException x)
            {
                MessageBox.Show(x.Message);
            }
        }

        void pd_PrintPage(object sender, PrintPageEventArgs e)
        {
            float leftMargin = e.MarginBounds.Left;
            float topMargin = e.MarginBounds.Top;
            FontFamily printingFont = FontFamily.GenericMonospace;

            Font f = new Font(printingFont, 10);

            float lineHeight = f.GetHeight(e.Graphics);

            int lineNo = 0;

            foreach (var line in dataFormattedForPrint)
            {
                e.Graphics.DrawString(line, f, Brushes.Black, leftMargin, topMargin + lineHeight * lineNo++);
            }
            e.HasMorePages = false;
        }

        private void PrintBill_Load(object sender, EventArgs e)
        {
            this.Text = "Print Bill - Bill No. " + billNo.ToString();
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            return;
        }
    }
}
